﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using MahApps.Metro.Controls;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    /// <summary>
    /// QuestionEditor.xaml 的交互逻辑
    /// </summary>
    public partial class QuestionEditor : MetroWindow
    {
        public QuestionEditor(List<QuestionInfo> questionInfos, MarkdownEditor masterEditor)
        {
            InitializeComponent();

            this.masterEditor = masterEditor;
            this.Title = Globals.AppName + " - 选择题编辑器";

            this.questionInfos = questionInfos;
            mtbNumber.Minimum = 1;
            mtbNumber.Maximum = questionInfos.Count;
            tbCount.Text = $"共 {questionInfos.Count.ToString()} 题";

            qEdits.Add(new QEdit() { ChoiceItemEdit = atbAnswer, ChoiceItemAnalyEdit = atbAnswerAnaly, });
            qEdits.Add(new QEdit() { ChoiceItemEdit = atbError1, ChoiceItemAnalyEdit = atbError1Analy, });
            qEdits.Add(new QEdit() { ChoiceItemEdit = atbError2, ChoiceItemAnalyEdit = atbError2Analy, });
            qEdits.Add(new QEdit() { ChoiceItemEdit = atbError3, ChoiceItemAnalyEdit = atbError3Analy, });

            anaTbxs.Add(atbAnswerAnaly);
            anaTbxs.Add(atbError1Analy);
            anaTbxs.Add(atbError2Analy);
            anaTbxs.Add(atbError3Analy);

            // 移除所有内置的快捷菜单——没用还丑陋
            atbTitle.ContextMenu = null;
            foreach (var qedit in qEdits)
            {
                qedit.ChoiceItemEdit.ContextMenu = null;
                qedit.ChoiceItemAnalyEdit.ContextMenu = null;
            }

            Loaded += QuestionEditor_Loaded;

            var cm = new ContextMenu();
            TextOptions.SetTextFormattingMode(cm, TextFormattingMode.Display);
            cm.FontFamily = new FontFamily("simsun");

            var miExpandSelection = new MenuItem()
            {
                Header = "扩选(_E)",
                Style = TryFindResource("MetroMenuItem") as Style,
            };
            miExpandSelection.Click += MiExpandSelection_Click;
            cm.Items.Add(miExpandSelection);
            cm.Items.Add(new Separator());

            var miGotoErrorItem01 = new MenuItem()
            {
                Header = "到错项 _1 解析",
                Style = TryFindResource("MetroMenuItem") as Style,
            };
            miGotoErrorItem01.Click += MiGotoErrorItem01_Click;
            cm.Items.Add(miGotoErrorItem01);

            var miGotoErrorItem02 = new MenuItem()
            {
                Header = "到错项 _2 解析",
                Style = TryFindResource("MetroMenuItem") as Style,
            };
            miGotoErrorItem02.Click += MiGotoErrorItem02_Click;
            cm.Items.Add(miGotoErrorItem02);

            var miGotoErrorItem03 = new MenuItem()
            {
                Header = "到错项 _3 解析",
                Style = TryFindResource("MetroMenuItem") as Style,
            };
            miGotoErrorItem03.Click += MiGotoErrorItem03_Click;
            cm.Items.Add(miGotoErrorItem03);

            cm.Items.Add(new Separator());

            var miDeleteSelectedText = new MenuItem()
            {
                Header = "删除(_D)",
                Style = TryFindResource("MetroMenuItem") as Style,
            };
            miDeleteSelectedText.Click += MiDeleteSelectedText_Click;
            cm.Items.Add(miDeleteSelectedText);

            var miDeleteToStart = new MenuItem()
            {
                Header = "删除到行首(_H)",
                Style = TryFindResource("MetroMenuItem") as Style,
                ToolTip = "按 Shift 和【[*]删除到行首】效果相同。",
            };
            miDeleteToStart.Click += MiDeleteToStart_Click;
            cm.Items.Add(miDeleteToStart);

            var miDeleteToEnd = new MenuItem()
            {
                Header = "删除到行尾(_T)",
                Style = TryFindResource("MetroMenuItem") as Style,
                ToolTip = "按 Shift 和【[*]删除到行尾】效果相同。",
            };
            miDeleteToEnd.Click += MiDeleteToEnd_Click;
            cm.Items.Add(miDeleteToEnd);

            cm.Items.Add(new Separator());

            var miDeleteToStartWithSelectedText = new MenuItem()
            {
                Header = "[*]删除到行首(_H)",
                Style = TryFindResource("MetroMenuItem") as Style,
                ToolTip = "连选中文本一起删除。",
            };
            miDeleteToStartWithSelectedText.Click += MiDeleteToStartWithSelectedText_Click;
            cm.Items.Add(miDeleteToStartWithSelectedText);

            var miDeleteToEndWithSelectedText = new MenuItem()
            {
                Header = "[*]删除到行尾(_T)",
                Style = TryFindResource("MetroMenuItem") as Style,
                ToolTip = "连选中文本一起删除。",
            };
            miDeleteToEndWithSelectedText.Click += MiDeleteToEndWithSelectedText_Click;
            cm.Items.Add(miDeleteToEndWithSelectedText);

            atbAnswerAnaly.Tag = cm;

            cm.PreviewKeyDown += Cm_PreviewKeyDown;

            this.Closing += QuestionEditor_Closing;
        }

        private void Cm_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Back:
                case Key.Delete:
                    {
                        MiDeleteSelectedText_Click(sender, e);
                        (sender as ContextMenu).IsOpen = false;
                        e.Handled = true;
                        break;
                    }
                case Key.D:
                    {
                        KeyStates ksLCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);
                        KeyStates ksRCtrl = Keyboard.GetKeyStates(Key.RightCtrl);

                        bool isCtrl = (ksLCtrl & KeyStates.Down) > 0 || (ksRCtrl & KeyStates.Down) > 0;
                        if (isCtrl)
                        {
                            (sender as ContextMenu).IsOpen = false;
                            e.Handled = true;
                        }
                        break;
                    }
            }
        }

        private MarkdownEditor masterEditor = null;

        private void MiExpandSelection_Click(object sender, RoutedEventArgs e)
        {
            foreach (var tbx in anaTbxs)
            {
                if (tbx.IsFocused)
                {
                    var rtxt = tbx.Text.Substring(tbx.SelectionStart + tbx.SelectionLength);
                    var nextMarkIndex = -1;
                    for (int i = 0; i < rtxt.Length; i++)
                    {
                        var c = rtxt[i];
                        if (";；.。".Contains(c))
                        {
                            nextMarkIndex = i;
                            break;
                        }
                    }

                    var tmpLength = tbx.SelectionLength + nextMarkIndex + 1;
                    if (nextMarkIndex >= 0 && tmpLength >= 0)
                    {
                        tbx.Select(tbx.SelectionStart, tmpLength);
                    }
                    else
                    {
                        //选中到行尾
                        tmpLength = tbx.Text.Length - tbx.SelectionStart;
                        if (tmpLength >= 0)
                        {
                            tbx.Select(tbx.SelectionStart, tmpLength);
                        }
                    }
                    var cm = tbx.Tag as ContextMenu;
                    if (cm != null)
                        cm.IsOpen = true;
                    return;
                }
            }
        }

        private void MiDeleteToEndWithSelectedText_Click(object sender, RoutedEventArgs e)
        {
            var tbx = atbAnswerAnaly;
            var len = tbx.SelectionLength;
            var newStart = tbx.SelectionStart + len;

            // 这个效果和按 Shift + Mi6 一样。
            tbx.Select(tbx.SelectionStart, tbx.Text.Length - tbx.SelectionStart);

            tbx.SelectedText = "";  // 删除到行尾不需要再选中什么了。这题基本结束。
            return;
        }

        private void MiDeleteToStartWithSelectedText_Click(object sender, RoutedEventArgs e)
        {
            var tbx = atbAnswerAnaly;
            var len = tbx.SelectionLength;

            tbx.Select(0, tbx.SelectionStart + len);
            // 这个效果和按 Shift + Mi5 一样。

            tbx.SelectedText = "";
            //删除到行首一般需要选中下一句。
            var rtxt = tbx.Text.Substring(tbx.SelectionStart);
            var end = -1;
            for (int i = 0; i < rtxt.Length; i++)
            {
                var c = rtxt[i];
                if (";；.。".Contains(c))
                {
                    end = i;
                    break;
                }
            }

            if (end >= 0)
            {
                tbx.Select(tbx.SelectionStart, end + 1);
            }
            else
            {
                tbx.Select(0, len);
            }
            return;
        }

        private void MiDeleteToEnd_Click(object sender, RoutedEventArgs e)
        {
            var tbx = atbAnswerAnaly;
            var len = tbx.SelectionLength;
            var newStart = tbx.SelectionStart + len;

            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            bool isShift = (ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0;

            if (isShift)
            {
                tbx.Select(tbx.SelectionStart, tbx.Text.Length - tbx.SelectionStart);
                // 按 Shift 连选中文本一起删除。
            }
            else
            {
                tbx.Select(newStart, tbx.Text.Length - newStart);
            }

            tbx.SelectedText = "";  // 删除到行尾不需要再选中什么了。这题基本结束。
            return;
        }

        private void MiDeleteToStart_Click(object sender, RoutedEventArgs e)
        {
            var tbx = atbAnswerAnaly;
            var len = tbx.SelectionLength;

            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            bool isShift = (ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0;

            if (isShift)
            {
                tbx.Select(0, tbx.SelectionStart + len);
                // 按 Shift 时连自身一并删除。
            }
            else
            {
                tbx.Select(0, tbx.SelectionStart);
            }

            tbx.SelectedText = "";
            //删除到行首一般需要选中下一句。
            var rtxt = tbx.Text.Substring(tbx.SelectionStart);
            var end = -1;
            for (int i = 0; i < rtxt.Length; i++)
            {
                var c = rtxt[i];
                if (";；.。".Contains(c))
                {
                    end = i;
                    break;
                }
            }

            if (end >= 0)
            {
                tbx.Select(tbx.SelectionStart, end + 1);
            }
            else
            {
                tbx.Select(0, len);
            }
            return;
        }

        private void MiDeleteSelectedText_Click(object sender, RoutedEventArgs e)
        {
            var tbx = atbAnswerAnaly;
            tbx.SelectedText = "";
            if (tbx.SelectionStart > 0)
            {
                var left = tbx.Text.Substring(0, tbx.SelectionStart).TrimEnd(new char[] { ',', '.', ';', '；', ' ', '　', '\t', });
                if (left.Length < tbx.SelectionStart)
                {
                    tbx.Select(left.Length, tbx.SelectionStart - left.Length);
                    tbx.SelectedText = "。";
                    tbx.Select(tbx.SelectionStart + 1, 0);
                }
            }
            return;
        }

        private void QuestionEditor_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (this.DialogResult.HasValue == false || this.DialogResult.Value == false)
            {
                var result = LMessageBox.Show("要将当前编辑的内容同步到主编辑器中吗？", Globals.AppName,
                    MessageBoxButton.YesNoCancel, MessageBoxImage.Question, "", null, this);
                if (result == MessageBoxResult.Yes)
                {
                    UpdateQuestion(mtbNumber.Value.Value);
                    // 先暂存数据，准备同步
                }
                else if (result == MessageBoxResult.Cancel)
                {
                    e.Cancel = true;  // 返回继续编辑。
                    return;
                }
                else if (result == MessageBoxResult.No)
                {
                    // 放弃数据，直接关闭窗口。
                    return;
                }
            }
            else
            {
                if (this.DialogResult.Value == true)
                {
                    UpdateQuestion(mtbNumber.Value.Value);
                    // 按下了 Submit 按钮，先暂存数据再关闭。
                }
                // 如果是按下了 Cancel 按钮，直接关闭。
            }
        }

        private void MiGotoErrorItem03_Click(object sender, RoutedEventArgs e)
        {
            btnToError3Analy_Click(sender, e);
        }

        private void MiGotoErrorItem02_Click(object sender, RoutedEventArgs e)
        {
            btnToError2Analy_Click(sender, e);
        }

        private void MiGotoErrorItem01_Click(object sender, RoutedEventArgs e)
        {
            btnToError1Analy_Click(sender, e);
        }

        private void QuestionEditor_Loaded(object sender, RoutedEventArgs e)
        {
            mtbNumber.Value = 1;
        }

        private List<QEdit> qEdits = new List<QEdit>();

        private List<QuestionInfo> questionInfos;
        /// <summary>
        /// 关闭窗口后，要从此属性获取修改后的数据。
        /// </summary>
        public List<QuestionInfo> QuestionInfos { get { return questionInfos; } }

        private string markdownImageLinkText = null;

        private void ShowQuestion()
        {
            if (mtbNumber.Value.HasValue == false)
            {
                LMessageBox.Show("请指定要显示哪一题。", Globals.AppName, MessageBoxButton.OK,
                    MessageBoxImage.Warning, "", "", this);
                return;
            }

            if (ipw != null)
            {
                ipw.Close();
            }

            var index = mtbNumber.Value.Value - 1;
            if (index < 0 || index >= questionInfos.Count) return;

            var qi = questionInfos[index];

            if (qi == null || qi.ChoiceItems.Count != qEdits.Count)
            {
                LMessageBox.ShowWarning("题支数量不是 4 个。不支持。");
                return;
            }

            if (string.IsNullOrEmpty(qi.MarkdownImagePath) == false)
            {
                qi.MarkdownImageLinkRealPath = masterEditor?.GetRealPathFromRelativeImagePath(qi.MarkdownImagePath);
            }

            var trimchars = new char[] { '\r', '\n', ' ', '　', '\t', };
            atbTitle.Text = qi.TitleString.Trim(trimchars);
            markdownImageLinkText = qi.MarkdownLinkText;

            for (int i = 0; i < qi.ChoiceItems.Count; i++)
            {
                var ci = qi.ChoiceItems[i];
                if (ci.IsAnswer)
                {
                    qEdits[0].ChoiceItemEdit.Text = ci.Text.Trim(trimchars);

                    qEdits[0].ChoiceItemAnalyEdit.Text = ci.AnalysisText.Trim(trimchars);
                }
            }

            int errorItemCount = 0;
            foreach (ChoiceItem ci in qi.ChoiceItems)
            {
                if (ci.IsAnswer == false)
                {
                    qEdits[errorItemCount + 1].ChoiceItemEdit.Text = ci.Text.Trim(trimchars);

                    qEdits[errorItemCount + 1].ChoiceItemAnalyEdit.Text = ci.AnalysisText.Trim(trimchars);
                    errorItemCount++;
                }
            }

            tbNumber.Text = $"{mtbNumber.Value.Value.ToString()}．";

            if (System.IO.File.Exists(qi.MarkdownImageLinkRealPath))
            {
                btnShowImage.Visibility = Visibility.Visible;
                btnShowImage.Tag = qi.MarkdownImageLinkRealPath;
            }
            else
            {
                btnShowImage.Visibility = Visibility.Hidden;
                btnShowImage.Tag = null;
            }

            atbAnswer.SelectAll();
            atbAnswerAnaly.Focus();

            if (qi.ShouldRemove)
            {
                tbShouldDelete.Text = "本题将被删除！！！";
                atbTitle.TextDecorations = TextDecorations.Strikethrough;
            }
            else
            {
                tbShouldDelete.Text = "";
                atbTitle.TextDecorations = null;
            }
        }

        private void mtbNumber_ValueChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            try
            {
                if (e.OldValue != null)
                {
                    int oldNum = (int)e.OldValue;
                    UpdateQuestion(oldNum);
                }
            }
            catch (Exception ex)
            {
                LMessageBox.Show(ex.Message);
            }

            ShowQuestion();
        }

        private void UpdateQuestion(int num)
        {
            if (num >= 1 && num <= questionInfos.Count)
            {
                var index = num - 1;
                var qi = questionInfos[index];
                qi.TitleString = $"{atbTitle.Text}\r\n\r\n{markdownImageLinkText}\r\n\r\n";
                for (int i = 0; i <= 3; i++)
                {
                    qi.ChoiceItems[i].IsAnswer = (qEdits[i].ChoiceItemEdit == atbAnswer);
                    qi.ChoiceItems[i].Text = qEdits[i].ChoiceItemEdit.Text;
                    qi.ChoiceItems[i].AnalysisText = qEdits[i].ChoiceItemAnalyEdit.Text;
                }
            }
        }

        private void btnFst_Click(object sender, RoutedEventArgs e)
        {
            if (questionInfos.Count <= 0) return;
            var destNum = 1;
            if (destNum < 1 || destNum > questionInfos.Count) return;

            mtbNumber.Value = destNum;
        }

        private void btnPre_Click(object sender, RoutedEventArgs e)
        {
            if (questionInfos.Count <= 0) return;
            var destNum = mtbNumber.Value - 1;
            if (destNum < 1 || destNum > questionInfos.Count) return;

            mtbNumber.Value = destNum;
        }

        private void btnNxt_Click(object sender, RoutedEventArgs e)
        {
            if (questionInfos.Count <= 0) return;
            var destNum = mtbNumber.Value + 1;
            if (destNum < 1 || destNum > questionInfos.Count) return;

            mtbNumber.Value = destNum;
        }

        private void btnLst_Click(object sender, RoutedEventArgs e)
        {
            if (questionInfos.Count <= 0) return;
            var destNum = questionInfos.Count;
            if (destNum < 1 || destNum > questionInfos.Count) return;

            mtbNumber.Value = destNum;
        }

        private void BtnOk_Click(object sender, RoutedEventArgs e)
        {
            if (mtbNumber.Value.HasValue == false) return;
            this.DialogResult = true;
            this.Close();
        }

        private void BtnCancel_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = false;
            this.Close();
        }

        private void MetroWindow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            KeyStates ksLAlt = Keyboard.GetKeyStates(Key.LeftAlt);
            KeyStates ksRAlt = Keyboard.GetKeyStates(Key.RightAlt);
            KeyStates ksLCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);
            KeyStates ksRCtrl = Keyboard.GetKeyStates(Key.RightCtrl);

            bool isCtrl, isShift, isAlt;

            isShift = (ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0;
            isCtrl = (ksLCtrl & KeyStates.Down) > 0 || (ksRCtrl & KeyStates.Down) > 0;
            isAlt = (ksLAlt & KeyStates.Down) > 0 || (ksRAlt & KeyStates.Down) > 0;

            switch (e.Key)
            {
                case Key.Escape:
                    {
                        if (!isCtrl && !isShift && !isAlt)
                        {
                            this.DialogResult = false;
                            return;
                        }
                        break;
                    }
                case Key.Enter:
                    {
                        if (isCtrl)
                        {
                            BtnOk_Click(sender, e);
                        }
                        //else  // 会和题号切换框冲突。
                        //{
                        //    var result = LMessageBox.Show("选择题各部分不支持换行操作。要继续编辑下一题吗？",
                        //        Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Question, "JumpToNextChoiceQuestion", null, this);

                        //    if (result != MessageBoxResult.Yes) return;

                        //    btnNxt_Click(sender, e);
                        //    e.Handled = true;
                        //}
                        break;
                    }
                case Key.PageDown:
                    {
                        if (isCtrl || isAlt) break;
                        if (isShift)
                        {
                            btnLst_Click(sender, e);
                        }
                        else
                        {
                            btnNxt_Click(sender, e);
                        }
                        e.Handled = true;
                        break;
                    }
                case Key.PageUp:
                    {
                        if (isCtrl || isAlt) break;
                        if (isShift)
                        {
                            btnFst_Click(sender, e);
                        }
                        else
                        {
                            btnPre_Click(sender, e);
                        }
                        e.Handled = true;
                        break;
                    }
                case Key.D0:
                    {
                        if (isCtrl)
                        {
                            btnToAnswerAnaly_Click(sender, e);
                            e.Handled = true;
                        }
                        break;
                    }
                case Key.D1:
                    {
                        if (isCtrl)
                        {
                            btnToError1Analy_Click(sender, e);
                            e.Handled = true;
                        }
                        break;
                    }
                case Key.D2:
                    {
                        if (isCtrl)
                        {
                            btnToError2Analy_Click(sender, e);
                            e.Handled = true;
                        }
                        break;
                    }
                case Key.D3:
                    {
                        if (isCtrl)
                        {
                            btnToError3Analy_Click(sender, e);
                            e.Handled = true;
                        }
                        break;
                    }
                case Key.B:  // Back，上一题
                case Key.P:  // Preview，上一题{
                    {
                        if (isCtrl)
                        {
                            btnPre_Click(sender, e);
                            e.Handled = true;
                        }
                        break;
                    }
                case Key.F:  // Forward，后（前进）一题
                case Key.N:  // Next，后一题
                    {
                        if (isCtrl)
                        {
                            btnNxt_Click(sender, e);
                            e.Handled = true;
                        }
                        break;
                    }
                case Key.Q:
                    {
                        if (isCtrl)
                        {
                            mtbNumber.Focus();
                            e.Handled = true;
                        }
                        break;
                    }
            }
        }

        private List<TextBox> anaTbxs = new List<TextBox>();

        private void btnToAnswerAnaly_Click(object sender, RoutedEventArgs e)
        {
            var isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            foreach (var tbx in anaTbxs)
            {
                var selText = tbx.SelectedText;
                selText = selText.Trim(new char[] { ',', '.', '，', '。', ';', '；', '\r', '\n', ' ', '　', '\t', }) + "。";
                if (tbx != atbAnswerAnaly && tbx.IsFocused && selText.Length > 0)
                {
                    atbAnswerAnaly.Select(atbAnswerAnaly.Text.Length, 0);
                    atbAnswerAnaly.SelectedText = selText;
                    atbAnswerAnaly.Select(atbAnswerAnaly.Text.Length, 0);

                    if (isCtrl == false)  // 按住 Ctrl 是复制，不然是移动。
                    {
                        tbx.SelectedText = "";
                        if (tbx.SelectionStart > 0)
                        {
                            var left = tbx.Text.Substring(0, tbx.SelectionStart).TrimEnd(new char[] { ',', '.', ';', '；', ' ', '　', '\t', });
                            if (left.Length < tbx.SelectionStart)
                            {
                                tbx.Select(left.Length, tbx.SelectionStart - left.Length);
                                tbx.SelectedText = "。";
                                tbx.Select(tbx.SelectionStart + 1, 0);
                            }
                        }

                        Regex reg = new Regex(@"[;.；。]{1,}");
                        var match = reg.Match(tbx.Text.Substring(tbx.SelectionStart));
                        if (match.Success && match.Index > 0)
                        {
                            tbx.Select(tbx.SelectionStart, match.Index + match.Length);
                            var cm = tbx.Tag as ContextMenu;
                            if (cm != null)
                                cm.IsOpen = true;
                        }
                    }
                    return;
                }
            }
        }

        private void btnToError1Analy_Click(object sender, RoutedEventArgs e)
        {
            var isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            foreach (var tbx in anaTbxs)
            {
                var selText = tbx.SelectedText;
                selText = selText.Trim(new char[] { ',', '.', '，', '。', ';', '；', '\r', '\n', ' ', '　', '\t', }) + "。";
                if (tbx != atbError1Analy && tbx.IsFocused && selText.Length > 0)
                {
                    atbError1Analy.Select(atbError1Analy.Text.Length, 0);
                    atbError1Analy.SelectedText = selText;
                    atbError1Analy.Select(atbError1Analy.Text.Length, 0);
                    if (isCtrl == false)  // 按住 Ctrl 是复制，不然是移动。
                    {
                        tbx.SelectedText = "";
                        if (tbx.SelectionStart > 0)
                        {
                            var left = tbx.Text.Substring(0, tbx.SelectionStart).TrimEnd(new char[] { ',', '.', ';', '；', ' ', '　', '\t', });
                            if (left.Length < tbx.SelectionStart)
                            {
                                tbx.Select(left.Length, tbx.SelectionStart - left.Length);
                                tbx.SelectedText = "。";
                                tbx.Select(tbx.SelectionStart + 1, 0);
                            }
                        }

                        Regex reg = new Regex(@"[;.；。]{1,}");
                        var match = reg.Match(tbx.Text.Substring(tbx.SelectionStart));
                        if (match.Success && match.Index > 0)
                        {
                            tbx.Select(tbx.SelectionStart, match.Index + match.Length);
                            var cm = tbx.Tag as ContextMenu;
                            if (cm != null)
                                cm.IsOpen = true;
                        }
                    }
                    return;
                }
            }
        }

        private void btnToError2Analy_Click(object sender, RoutedEventArgs e)
        {
            var isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            foreach (var tbx in anaTbxs)
            {
                var selText = tbx.SelectedText;
                selText = selText.Trim(new char[] { ',', '.', '，', '。', ';', '；', '\r', '\n', ' ', '　', '\t', }) + "。";
                if (tbx != atbError2Analy && tbx.IsFocused && selText.Length > 0)
                {
                    atbError2Analy.Select(atbError2Analy.Text.Length, 0);
                    atbError2Analy.SelectedText = selText;
                    atbError2Analy.Select(atbError2Analy.Text.Length, 0);
                    if (isCtrl == false)  // 按住 Ctrl 是复制，不然是移动。
                    {
                        tbx.SelectedText = "";
                        if (tbx.SelectionStart > 0)
                        {
                            var left = tbx.Text.Substring(0, tbx.SelectionStart).TrimEnd(new char[] { ',', '.', ';', '；', ' ', '　', '\t', });
                            if (left.Length < tbx.SelectionStart)
                            {
                                tbx.Select(left.Length, tbx.SelectionStart - left.Length);
                                tbx.SelectedText = "。";
                                tbx.Select(tbx.SelectionStart + 1, 0);
                            }
                        }

                        Regex reg = new Regex(@"[;.；。]{1,}");
                        var match = reg.Match(tbx.Text.Substring(tbx.SelectionStart));
                        if (match.Success && match.Index > 0)
                        {
                            tbx.Select(tbx.SelectionStart, match.Index + match.Length);
                            var cm = tbx.Tag as ContextMenu;
                            if (cm != null)
                                cm.IsOpen = true;
                        }
                    }
                    return;
                }
            }
        }

        private void btnToError3Analy_Click(object sender, RoutedEventArgs e)
        {
            var isCtrl = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl);
            foreach (var tbx in anaTbxs)
            {
                var selText = tbx.SelectedText;
                selText = selText.Trim(new char[] { ',', '.', '，', '。', ';', '；', '\r', '\n', ' ', '　', '\t', }) + "。";
                if (tbx != atbError3Analy && tbx.IsFocused && selText.Length > 0)
                {
                    atbError3Analy.Select(atbError3Analy.Text.Length, 0);
                    atbError3Analy.SelectedText = selText;
                    atbError3Analy.Select(atbError3Analy.Text.Length, 0);
                    if (isCtrl == false)  // 按住 Ctrl 是复制，不然是移动。
                    {
                        tbx.SelectedText = "";
                        Regex reg = new Regex(@"[;.；。]{1,}");
                        var match = reg.Match(tbx.Text.Substring(tbx.SelectionStart));
                        if (match.Success && match.Index > 0)
                        {
                            tbx.Select(tbx.SelectionStart, match.Index + match.Length);
                            var cm = tbx.Tag as ContextMenu;
                            if (cm != null)
                                cm.IsOpen = true;
                        }

                        if (tbx.SelectionStart > 0)
                        {
                            var left = tbx.Text.Substring(0, tbx.SelectionStart).TrimEnd(new char[] { ',', '.', ';', '；', ' ', '　', '\t', });
                            if (left.Length < tbx.SelectionStart)
                            {
                                tbx.Select(left.Length, tbx.SelectionStart - left.Length);
                                tbx.SelectedText = "。";
                                tbx.Select(tbx.SelectionStart + 1, 0);
                            }
                        }
                    }
                    return;
                }
            }
        }

        private void atbAnswerAnaly_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var cm = atbAnswerAnaly.Tag as ContextMenu;
            if (cm != null && atbAnswerAnaly.SelectedText.Length > 0)
            {
                cm.IsOpen = true;
                e.Handled = true;
            }
        }

        private void btnDelete_Click(object sender, RoutedEventArgs e)
        {
            if (mtbNumber.Value.HasValue == false) return;

            if (mtbNumber.Value.Value >= 1 && mtbNumber.Value.Value <= questionInfos.Count)
            {
                questionInfos[mtbNumber.Value.Value - 1].ShouldRemove = true;
                tbShouldDelete.Text = "本题将被删除！！！";
                atbTitle.TextDecorations = TextDecorations.Strikethrough;
            }
        }

        private void btnUnDelete_Click(object sender, RoutedEventArgs e)
        {
            if (mtbNumber.Value.HasValue == false) return;

            if (mtbNumber.Value.Value >= 1 && mtbNumber.Value.Value <= questionInfos.Count)
            {
                questionInfos[mtbNumber.Value.Value - 1].ShouldRemove = false;
                tbShouldDelete.Text = "";
                atbTitle.TextDecorations = null;
            }
        }

        private ImagePreviewWindow ipw = null;

        private void btnShowImage_Click(object sender, RoutedEventArgs e)
        {
            if (btnShowImage.Tag == null || System.IO.File.Exists(btnShowImage.Tag as string) == false)
            {
                return;
            }

            ipw = new ImagePreviewWindow(btnShowImage.Tag as string, "")
            {
                Owner = App.Current.MainWindow,
                WindowStartupLocation = WindowStartupLocation.CenterOwner,
                WindowState = WindowState.Normal,
                Height = 480,
                Width = 640,
            };
            ipw.Show();  //允许多张图片同时演示
        }

        private void btnDelToStart_Click(object sender, RoutedEventArgs e)
        {
            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            bool isShift = (ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0;

            if (isShift)
            {
                MiDeleteToStartWithSelectedText_Click(sender, e);
            }
            else
            {
                MiDeleteToStart_Click(sender, e);
            }
        }

        private void btnDelToEnd_Click(object sender, RoutedEventArgs e)
        {
            KeyStates ksRShift = Keyboard.GetKeyStates(Key.RightShift);
            KeyStates ksLShift = Keyboard.GetKeyStates(Key.LeftShift);
            bool isShift = (ksLShift & KeyStates.Down) > 0 || (ksRShift & KeyStates.Down) > 0;

            if (isShift)
            {
                MiDeleteToEndWithSelectedText_Click(sender, e);
            }
            else
            {
                MiDeleteToEnd_Click(sender, e);
            }
        }

        private string replaceDictInitContent = "；这是用于在选择题编辑器中进行替换的字典。\r\n" +
                                 "；在此文档中，以分号开头的行是注释行，会被忽略。\r\n" +
                                 "；空行也会被忽略。\r\n" +
                                 "；查找规则行应写成“查找：xxx”开头的行，其中“xxx”为查找规则。\r\n" +
                                 "；替换规则可以省略，或者写成“替换：yyy”开头的行，其中“yyy”为替换文本。\r\n" +
                                 "；注意：这里的替换和主编辑器的【批量替换】不同！" +
                                 "；这个字典进行查找时【不支持正则表达式】，也【不支持共用替换规则】！\r\n" +
                                 "；如果不写替换规则，视为替换为空字符串。\r\n";

        private string replaceDictSourceText = "";

        /// <summary>
        /// 仅用于此处。
        /// </summary>
        internal class ReplaceRule
        {
            internal string FindRule { get; set; } = "";
            internal string Replacement { get; set; } = "";
        }

        private void btnReplaceAnaly_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            var path = Globals.PathOfUserFolder + "选择题替换字典.txt";
            if (System.IO.File.Exists(path) == false)
            {
                string content = replaceDictInitContent;
                System.IO.File.WriteAllText(path, content, Encoding.UTF8);
            }

            System.Diagnostics.Process.Start("explorer.exe", "\"" + path + "\"");
        }

        private void btnReplaceAnaly_Click(object sender, RoutedEventArgs e)
        {
            if (string.IsNullOrEmpty(replaceDictSourceText))
            {
                btnReadReplaceAnaly_Click(sender, e);

                if (string.IsNullOrEmpty(replaceDictSourceText))
                    return;
            }

            ReplaceAnalysText();
        }

        private void ReplaceAnalysText()
        {
            var lines = replaceDictSourceText.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

            var rules = new List<ReplaceRule>();
            var preRule = new ReplaceRule();
            foreach (var line in lines)
            {
                if (line.StartsWith(";") || line.StartsWith("；") || string.IsNullOrEmpty(line)) continue;

                if (line.StartsWith("查找：") || line.StartsWith("查找:"))
                {
                    if (string.IsNullOrEmpty(preRule.FindRule) == false && string.IsNullOrEmpty(preRule.Replacement))
                    {
                        rules.Add(preRule);           // 不写替换规则以空字符串为替换规则。
                        preRule = new ReplaceRule();
                    }

                    var tail = line.Substring(3);
                    if (tail.Length <= 0) continue;

                    preRule.FindRule = tail;
                    continue;
                }

                if (line.StartsWith("替换：") || line.StartsWith("替换:"))
                {
                    if (string.IsNullOrEmpty(preRule.FindRule)) continue;

                    //var tail = line.Substring(3);
                    //if (tail.Length <= 0) continue;  // 这个不能加，否则就没有“替换为空字符串”的功能了。

                    preRule.Replacement = line.Substring(3);  // 不写替换规则视为空，写“替换：”也为空。
                    rules.Add(preRule);
                    preRule = new ReplaceRule();
                    continue;
                }
            }

            if (string.IsNullOrEmpty(preRule.FindRule) == false && string.IsNullOrEmpty(preRule.Replacement))
            {
                rules.Add(preRule);
            }

            var txt = atbAnswerAnaly.Text;
            for (int i = 0; i < rules.Count; i++)
            {
                var rule = rules[i];
                txt = txt.Replace(rule.FindRule, rule.Replacement);
            }

            atbAnswerAnaly.Text = txt;
        }

        private void btnReadReplaceAnaly_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var path = Globals.PathOfUserFolder + "选择题替换字典.txt";
                if (System.IO.File.Exists(path))
                {
                    replaceDictSourceText = System.IO.File.ReadAllText(path, Encoding.UTF8);
                }
                else
                {
                    replaceDictSourceText = "";
                }
            }
            catch (Exception ex)
            {
                replaceDictSourceText = "";
                LMessageBox.ShowWarning("未能读入替换字典！错误消息如下：\r\n\r\n" + ex.Message);
            }
        }
    }

    public class QEdit
    {
        public TextBox ChoiceItemEdit { get; set; }
        public TextBox ChoiceItemAnalyEdit { get; set; }
    }

    public class QuestionInfo : Question
    {
        public QuestionInfo(Match match, string titleString, string bodyString, bool shouldRandom = false) : base(titleString, bodyString, shouldRandom)
        {
            this.Match = match;
        }
        public Match Match { get; set; }
        public bool ShouldRemove { get; set; } = false;
    }
}
